#include "./include/S_printModule@windows.h"
#include "./include/producer_consumer.h"
#include "./include/Semaphore_t.h"
#include <iostream>
#include <iomanip>
#include <string.h>

using namespace std;

// int scroller=0;  // 滚动输出控制器

OutputStorage::OutputStorage(int row, int col)
{
    this->start=0;
    this->next=0;
    this->row=0;
    this->col=0;
    if(row<100 && col<100) {
        this->row=row;
        this->col=col;
    }
    
}

void OutputStorage::addOneStr(const char *str, const int isCmd)
{
    if(str) {
        if(isCmd) {
            storeCmd(outputBuffer[next], str);
        } else {
            strcpy(outputBuffer[next], str);
        }
        next = (next+1) % row;
        start = (next==start) ? (next+1)%row : start;
    }
}

void OutputStorage::updataInputRegion(COORD &position,int isEnd)
{
    hideCursor();
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
    print();
    setCurInputPosition(); 
    // 如果还没有结束，则输出命令提示符
    if( 0==isEnd ) {
        printPrompt();
    }
}

void OutputStorage::updataOutputRegion(COORD &position) {
    hideCursor();
    clearOutputRegion(position);
    COORD position_temp;
    HANDLE _out_h = GetStdHandle(STD_OUTPUT_HANDLE);
    position_temp.X=position.X;
    position_temp.Y=position.Y;

    
    int i=this->start;
    SetConsoleCursorPosition(_out_h, position_temp);
    cout.setf(ios::left);
    // if(scroller%2) {
    //     cout << setw(60) << setfill(' ') << " " ;
    //     position_temp.Y += 1;
    // } 
    while(i!=this->next) {
        SetConsoleCursorPosition(_out_h, position_temp);
        cout << setw(60) << setfill(' ') << outputBuffer[i] ;
        i = (i+1) % this->row;
        position_temp.Y += 1;
    }
    // scroller = (scroller+1) % 1333;
}

void OutputStorage::cmdParse(int &suspend, int &speed, const char *cmd, HANDLE &h)
{
    char preStr[15]={};
    char str[60]={};
    if('p'==cmd[0] || 'P'==cmd[0]) {
        strcpy(preStr, "    Producer");
    }else {
        strcpy(preStr,"    Consumer");
    }

    if('s'==cmd[3] || 'S'==cmd[3]) {
        // 设置生产者挂起标志为1，则由线程自己挂起
        suspend=1;
        sprintf(str,"%s will be suspended!",preStr);
        addOneStr(str,0);

    } else if( ('r'==cmd[3] || 'R'==cmd[3]) && suspend ) {
        // 如果生产者线程已经被挂起，则恢复运行
        ResumeThread(h);
        suspend=0;
        sprintf(str,"%s will run again!",preStr);
        addOneStr(str,0);

    } else if('w'==cmd[3] || 'W'==cmd[3]) {
        // 设置生产者生产数据的速度
        int num=0;
        for(int i=5; cmd[i]; i++) {
            if('0'<=cmd[i] && cmd[i]<='9') {
                num = num*10 + (cmd[i]-'0');
            } else {
                // 非数字，则说明输入非法，跳出循环
                addOneStr("    unknow command, please check and input again.",0);
                num=-1;
                break;
            }
        }
        speed=num; // 设置生产者生产数据的速度
    } else {
        // 输入的命令无法识别
        addOneStr("    unknow command, please check and input again.",0);
    }
}

void OutputStorage::print()
{
    int i=start;
    cout.setf(ios::left);
    while(i!=next) {
        cout << setw(col) << setfill(' ') <<outputBuffer[i] << endl;
        i=(i+1)%row;
    }
}

////////////////////////////////////////////////////////////////////////////////
//////////////////////////                     /////////////////////////////////
//////////////////////////    其他输出控制模块  /////////////////////////////////
//////////////////////////                     /////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*
 * 定义控制台互斥操作的信号量
 * 保证输入输出的有序
 */
Semaphore_t console_mutex=1;

/*
 * 定义用于 windows 控制台输出的全局变量
 */
HANDLE out_h;   // 标准输出句柄
CONSOLE_SCREEN_BUFFER_INFO screen_bInfo;  // 控制台屏幕缓冲区信息
COORD buf_position;       // 缓冲区第一个数据行输出的位置
COORD flag_positon;       // 标记位置
COORD pi_position;        // 生产者下标 pi 的输出位置
COORD ci_position;        // 消费者下标 ci 的输出位置
COORD output_position;    // 输出区起始位置
COORD p_position;         // 生产者当前输出位置
COORD c_position;         // 消费者当前输出位置
COORD input_position;     // 输入区起始位置
COORD cur_input_position; // 当前输入位置

/*
 * 函数功能：
 *     控制台初始化
 * 参数：
 *     无
 * 返回值：
 *     void
 */
void initConsole( )
{
    system("mode con cols=140 lines=40");
    out_h=GetStdHandle(STD_OUTPUT_HANDLE);
    cout << endl << endl;

    // 打印生产者下标 pi 
    cout << "\t   ";
    GetConsoleScreenBufferInfo(out_h, &screen_bInfo);
    pi_position.X=screen_bInfo.dwCursorPosition.X;
    pi_position.Y=screen_bInfo.dwCursorPosition.Y;
    buf_position.X=pi_position.X;
    buf_position.Y=pi_position.Y+1;
    cout << "p   " << endl ;
    
    // 打印表头行
    cout << "\t";
    for(int i=0; i<BUFFER_SIZE; i++) {
        cout << "+------" ;
    }
    cout << "+" << "  \t" ;
    
    // 打印标志框头
    // cout << "+-----+" ;
    cout << endl;

    cout << "\t" ;
    for(int i=0; i<BUFFER_SIZE; i++) {
            cout << "|      "  ;
    }
    cout << "|" << "  \t" ;
    // cout << "|  " ;
    // GetConsoleScreenBufferInfo(out_h, &screen_bInfo);
    // flag_positon.X=screen_bInfo.dwCursorPosition.X;
    // flag_positon.Y=screen_bInfo.dwCursorPosition.Y;
    // cout << " " << "  |" ;
    cout << endl;

    // 打印表尾行
    cout << "\t";
    for(int i=0; i<BUFFER_SIZE; i++) {
        cout << "+------" ;
    }
    cout << "+" << "  \t" ;
    // cout << "+-----+" ;
    cout << endl;

    // 打印消费者下标 ci 
    cout << "\t   " ;
    GetConsoleScreenBufferInfo(out_h, &screen_bInfo);
    ci_position.X=screen_bInfo.dwCursorPosition.X;
    ci_position.Y=screen_bInfo.dwCursorPosition.Y;
    cout << "c   " << endl ;
    cout << endl << endl;

    // 设置输出位置的初始值
    GetConsoleScreenBufferInfo(out_h, &screen_bInfo);
    output_position.X=0;
    output_position.Y=screen_bInfo.dwCursorPosition.Y;

    SetConsoleCursorPosition(out_h,output_position);
    cout << "[producer thread]: " ;
    output_position.X += 60;
    SetConsoleCursorPosition(out_h,output_position);
    cout << "[consumer thread]: " << endl;
    output_position.Y += 1;
    output_position.X=0;

    p_position.X=0;
    p_position.Y=output_position.Y;
    c_position.X=p_position.X+60;
    c_position.Y=p_position.Y;

    // 命令输入区
    input_position.X=0;
    input_position.Y=output_position.Y + OUTPUT_REGION_SIZE;

    helpInfo();

    SetConsoleCursorPosition(out_h,input_position);
    cout << "[main thread]:" << endl ;
    input_position.Y += 1;
    cout << "[cmd] #: ";
    GetConsoleScreenBufferInfo(out_h, &screen_bInfo);
    cur_input_position.X=screen_bInfo.dwCursorPosition.X;
    cur_input_position.Y=screen_bInfo.dwCursorPosition.Y;
}

/*
 * 函数功能：
 *    存储用户输入的命令
 */
void storeCmd(char *dst, const char *src)
{
    strcpy(dst, "[cmd] #: ");
    int k=9;
    for(int i=0; src[i]; i++) {
        dst[k++]=src[i];
    }
    dst[k]='\0'; 
    dst[k++]=0;  
}


/*
 * 隐藏光标
 */
void hideCursor()
{
    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(out_h,&cursorInfo);
    cursorInfo.bVisible=FALSE;
    SetConsoleCursorInfo(out_h,&cursorInfo);
}

/*
 * 显示光标
 */
void showCursor()
{
    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(out_h,&cursorInfo);
    cursorInfo.bVisible=TRUE;
    SetConsoleCursorInfo(out_h,&cursorInfo);
}

/*
 * 设置输入光标的位置
 */
void setCurInputPosition() 
{
    GetConsoleScreenBufferInfo(out_h, &screen_bInfo);
    cur_input_position.X=9;
    cur_input_position.Y=screen_bInfo.dwCursorPosition.Y;
}

/*
 * 函数功能：
 *    输出命令提示符
 */
void printPrompt()
{
    cout.setf(ios::left);
    cout << setw(50) << setfill(' ') << "[cmd] #: " ;
    setCurInputPosition();
}


/*
 * 可视化生产者-消费者操作
 */
void visual2console(int data, char ch)
{
    P(&console_mutex);
    hideCursor();
    COORD position;
    switch(ch)
    {
        case 'P':
        case 'p':
            position.X = pi_position.X;
            position.Y = pi_position.Y+2;
            SetConsoleCursorPosition(out_h,position);
            cout << setw(2) << data;
            position.Y -= 2;
            break;
        case 'C':
        case 'c':
            position.X = ci_position.X;
            position.Y = ci_position.Y-2;
            SetConsoleCursorPosition(out_h,position);
            cout << "  " ;
            position.Y += 2;
            break;
    }
    SetConsoleCursorPosition(out_h,position);
    cout << "  ";
    if( position.X+7 > buf_position.X + 7*(BUFFER_SIZE-1) ) {
        position.X=buf_position.X;
    } else {
        position.X += 7;
    }
    if('p'==ch || 'P'==ch) {
        pi_position.X=position.X;
        pi_position.Y=position.Y;
    } else {
        ci_position.X=position.X;
        ci_position.Y=position.Y;
    }
    SetConsoleCursorPosition(out_h,position);
    cout << ch << " " ;

    V(&console_mutex);
}

/*
 * 函数功能：
 *     输出帮助信息
 */
void helpInfo()
{
    char info[][100]={
        "usage: target param [number]\n", 
        "  target is producer or consumer. ", 
        "  you can use 'p' or 'P' on behalf of producer, ", 
        "  otherwise 'c' or 'C' on behalf of consumer.\n", 
        "  param is listed below: ", 
        "      -s or -S    # suspended the thread", 
        "      -r or -R    # Resume the thread", 
        "      -w or -W    # waite the thread, you must appoint a number behind\n", 
        "  number is optional.",
        "  if you use param '-w' or 'W', it must be appoint as an integer.",
        "notes: you can type '@' to end the whole program"
        "\0",
        0
    };

    COORD info_position;
    info_position.X=60;
    info_position.Y=input_position.Y;

    P(&console_mutex);
    SetConsoleCursorPosition(out_h,info_position);
    for(int i=0; info[i] && info[i][0]!='\0'; i++){
        cout << "|  " << info[i];
        (info_position.Y)++;
        SetConsoleCursorPosition(out_h,info_position);
    }
    cout << "|" << endl;
    V(&console_mutex);
}

void clearOutputRegion(COORD &position)
{
    COORD position_tmp;
    position_tmp.X=position.X;
    position_tmp.Y=position.Y;

    // P(&console_mutex);
    cout.setf(ios::left);
    for(int i=0; i<OUTPUT_REGION_SIZE-1; i++) {
        SetConsoleCursorPosition(out_h,position_tmp);
        cout << setw(60) << setfill(' ') << " ";
        position_tmp.Y += 1;
    }
    // V(&console_mutex);
}
